<template>
  <div>
    <div class="item-box" v-for="item in treeOptions" :key="item.key">
      <input type="radio" :id="`${item.key}`" name="tree-item" hidden />
      <label
        v-if="state.isMenu"
        :for="`${item.key}`"
        class="title title-menu"
        @click="toggleItem(item)"
      >
        <p :style="{ paddingLeft: padding + 'px' }">{{ item.label }}</p>
        <div v-if="item.isFolder" class="icon-triangle" :class="{ 'icon-open': item.isOpen }"></div>
      </label>

      <label v-else :for="`${item.key}`" class="title title-default" @click="toggleItem(item)">
        <div
          v-if="item.isFolder"
          class="icon-triangle"
          :style="{ left: padding + 'px' }"
          :class="{ 'icon-open': item.isOpen }"
        ></div>
        <p :style="{ marginLeft: padding + 16 + 'px' }">{{ item.label }}</p>
      </label>
      <div class="radio-box" :class="{ 'radio-box-show': item.isOpen }">
        <div style="min-height: 0">
          <Tree
            v-if="item.children"
            :type="type"
            :tree-options="item.children"
            :padding="padding + 14"
            @click-item="$emit('clickItem', $event)"
          />
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
export interface TreeOption {
  key: number | string
  label: string
  isFolder?: boolean
  children?: TreeOption[]
  isOpen?: boolean
}

interface Props {
  treeOptions: Array<TreeOption>
  padding?: number
  isAccordion?: boolean
  type?: 'default' | 'menu'
}

const props = withDefaults(defineProps<Props>(), {
  treeOptions: () => [],
  padding: 20,
  isAccordion: false,
  type: 'default'
})

const emit = defineEmits(['clickItem'])

const state = ref({
  isMenu: false
})

onMounted(() => {
  props.treeOptions.forEach((item) => {
    item.isOpen = false
    if (item?.children?.length) {
      item.isFolder = true
    }
  })

  if (props.type === 'menu') {
    state.value.isMenu = true
  }
})

const toggleItem = (item: TreeOption) => {
  if (item.isFolder) {
    if (props.isAccordion) {
      for (const p of props.treeOptions) {
        if (p.key === item.key) {
          p.isOpen = !p.isOpen
        } else {
          p.isOpen = false
        }
      }
    } else {
      item.isOpen = !item.isOpen
    }
  } else {
    emit('clickItem', item)
  }
}
</script>

<style scoped lang="scss">
$tree-item-height: 30px;
$tree-transition-duration: 0.4s;

.item-box {
  color: #242527;
  font-size: 14px;
  position: relative;

  .title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    transition: $tree-transition-duration;
    height: $tree-item-height;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    cursor: pointer;
    position: relative;

    &::before {
      content: '';
      position: absolute;
      height: 90%;
      width: calc(100% - 15px);
      margin: 0 6px;
      border-radius: 3px;
      transition: $tree-transition-duration;
    }

    .icon-triangle {
      content: '';
      width: 6px;
      height: 6px;
      border-top: 3px solid transparent;
      border-left: 3px solid transparent;
      border-right: 3px solid #242527;
      border-bottom: 3px solid #242527;
      transform: rotate(-45deg);
      transition: 0.2s;
      position: absolute;
      right: 3px;
    }

    .icon-open {
      transform: rotate(45deg);
    }

    p {
      padding: 4px;
      border-radius: 3px;
      transition: $tree-transition-duration;
    }
  }
}

.title-menu {
  &:hover::before {
    background: lighten($main-color, 25%);
    z-index: -99;
  }
}

.title-default {
  justify-content: left;
  &:hover > p {
    background: lighten($main-color, 25%);
  }
}

input[type='radio']:checked + .title-menu::before {
  background: lighten($main-color, 25%);
  z-index: -99;
}

input[type='radio']:checked + .title-default > p {
  background: lighten($main-color, 25%);
}

.radio-box {
  overflow: hidden;
  display: grid;
  grid-template-rows: 0fr;
  transition: $tree-transition-duration;
}

.radio-box-show {
  grid-template-rows: 1fr;
}
</style>
